﻿using System;

namespace Ewk.Math.Algebra.Algorithms.Matrices.Adjugate
{
    class LaplaceAdjugateFormula<T> : IAdjugateComputer<T>
        where T : struct, IComparable, IFormattable, IConvertible, IComparable<T>, IEquatable<T>
    {
        #region Implementation of IAdjugateComputer<T>

        /// <summary>
        /// Computes the adjugate of the specified <see cref="Matrix{T}"/>.
        /// </summary>
        /// <param name="matrix">The <see cref="Matrix{T}"/> to calculate the adjugate from.</param>
        /// <returns>A <see cref="Matrix{T}"/> that represents the adjugate of the specified <see cref="Matrix{T}"/>.</returns>
        public Matrix<T> ComputeAdjugate(Matrix<T> matrix)
        {
            if (matrix == null) return null;

            if (!matrix.IsSquared)
            {
                throw new InvalidOperationException("The matrix must be squared.");
            }

            var cofactorMatrix = new Matrix<T>(matrix.RowCount, matrix.ColumnCount);

            Matrix<T>.Iterate(
                matrix.RowCount,
                matrix.ColumnCount,
                (i, j) =>
                    {
                        var minorMatrix = Matrix<T>.Minor(matrix, i, j);
                        var sign = System.Math.Pow(-1, i + j);

                        cofactorMatrix[i, j] = sign > 0
                                                   ? cofactorMatrix[i, j] + Matrix<T>.ComputeDeterminant(minorMatrix)
                                                   : cofactorMatrix[i, j] - Matrix<T>.ComputeDeterminant(minorMatrix);
                    });

            return cofactorMatrix.Transpose();
        }

        #endregion
    }
}